package com.hivclassifier.models;

import weka.core.Instance;

import com.hivclassifier.utils.Blosum;
import com.hivclassifier.utils.DistanceMatrix;


public class HivClassModel {

	/**
	 * <b>11/25 rule</b>
	 * 
	 * <li>11th or 25th position are positively charged residues
	 * (Argnine (R), Lysine (K), Histidine (H)) - X4 - true</li>
	 * <li>otherwise - R5 - false</li>
	 */
	public boolean chargeRule;

	/**
	 * <b>+1 positive charge to basic residues (Arginine, Lysine, Histidine), a -1
	 * negative charge to the acidic residues (Aspartic acid (D) and Glutamic acid (E))</b>
	 * 
	 * <li>>0 - X4</li>
	 * <li>0<= - R5</li>
	 */
	public int netCharge;

	/**
	 * <b>Overall V3 loop length contributes to viral phenotype (gap number is
	 * inversely related to sequence length)</b>
	 * 
	 * <li>values differ with training of the model</li>
	 */
	public int numberOfGaps;

	/**
	 * <b>Pairwise distance between a sequence and an R5 consensus sequence</b>
	 * 
	 * <li>uses the DistanceMatrix.java</li>
	 */
	public double gDFromConsSeq;
	
	public enum CoreceptorEnums {
		CXCR4 ("CXCR4"),
		CCR5 ("CCR5"),
		DUAL ("DUAL");
		
		String value;
		
		CoreceptorEnums(String value) {
			this.value = value;
		}
	}
	
	public HivClassModel(){}
	
	public HivClassModel(Instance instance) {
		
		String attributes[] = instance.toString().replace("',", "").replace("'", "").split(",");
		
		chargeRule = isResiduePositivelyCharged(attributes[12]) 
						|| isResiduePositivelyCharged(attributes[26]);
		
		numberOfGaps = instance.toString().split("-").length - 1;
		
		for (int i = 1; i < 40; i++) {
			if (isResidueNegativelyCharged(attributes[i])) {
				netCharge--;
			} else if (isResiduePositivelyCharged(attributes[i])) {
				netCharge++;
			}
		}
		
		double[][] distances = new double[attributes.length][attributes.length];
		
		// put amino acids distances in the matrix
		for (int i = 0; i < 40; i++) {
			for (int j = 0; j < 40; j++) {
				distances[i][j] = Blosum.getDistance(attributes[i + 1].toCharArray()[0], 
													DistanceMatrix.consensusCcr5Sequence.charAt(j));
			}
		}
		
		gDFromConsSeq = new DistanceMatrix(distances).meanDistance();
	}
	
	public boolean isResiduePositivelyCharged(String residue) {
		if (residue.equalsIgnoreCase("R")) {
			return true;
		} else if (residue.equalsIgnoreCase("K")) {
			return true;
		} else if (residue.equalsIgnoreCase("H")) {
			return true;
		}
		
		return false;
	}
	
	public boolean isResidueNegativelyCharged(String residue) {
		if (residue.equalsIgnoreCase("D")) {
			return true;
		} else if (residue.equalsIgnoreCase("E")) {
			return true;
		}
		
		return false;
	}
	
	@Override
	public String toString() {
		return chargeRule + " ; " + numberOfGaps + " ; " + netCharge + " ; " + gDFromConsSeq; 
	}
}
